package com.jxpanda.infrastructure.model.web;

import lombok.*;

import java.io.Serializable;
import java.util.Collections;
import java.util.function.Consumer;

/**
 * 响应的包装对象
 * 这个对象的设计思路是相对封闭的，所以不提供setter函数，也不开放构造器
 * 只允许使用工厂函数创建对象
 *
 * @author Panda
 */
@Getter
@SuppressWarnings("unchecked")
public final class Response<T> implements Serializable {

    /**
     * 返回值code
     */
    private final int code;
    /**
     * 成功/失败
     * 基于code来计算
     */
    private final boolean success;
    /**
     * 返回的数据
     */
    private final T data;
    /**
     * 返回给用户的消息
     */
    @With
    private final String message;

    /**
     * 扩展参数，用来处理一些特殊情况的
     */
    @With
    private final Object extend;


    public Response(int code, boolean success, T data, String message, Object extend) {
        this.code = code;
        this.success = success;
        this.message = message == null ? "" : message;
        this.data = data == null ? (T) Collections.EMPTY_MAP : data;
        this.extend = extend == null ? Collections.EMPTY_MAP : extend;
    }

    /**
     * 私有化构造器
     * 这个对象的设计思路是只允许使用工厂函数创建
     * 暂时不开放构造器
     * 以后如果要增加其他code的返回值，以后再枚举，然后再考虑如何实现
     */
    private Response(Code code, T data, String message, Object extend) {
        this(code.code, code.success, data, message, extend);
    }

    private Response(Code code, T data) {
        this(code, data, code.message, null);
    }

    private Response(Code code, T data, String message) {
        this(code, data, message, null);
    }

    public Response<T> then(Consumer<? super T> action) {
        action.accept(this.data);
        return this;
    }

    /**
     * 成功，但是不需要返回内容
     * 返回200
     */
    public static <T> Response<T> ok() {
        return new Response<>(Code.NO_CONTENT, null);
    }

    /**
     * 成功，返回200
     */
    public static <T> Response<T> ok(T data) {
        return new Response<>(Code.OK, data);
    }

    /**
     * 成功，返回200
     */
    public static <T> Response<T> ok(Code code, T data) {
        if (!code.isSuccess()) {
            throw new RuntimeException("CODE NOT ACCESS");
        }
        return new Response<>(code, data);
    }

    public static <T> Response<T> ok(T data, String message) {
        return new Response<>(Code.OK, data, message);
    }

    public static <T> Response<T> ok(T data, String message, Object extend) {
        return new Response<>(Code.OK, data, message, extend);
    }

    /**
     * 失败，通常是入参检查错误，返回422
     */
    public static <T> Response<T> failed(String message) {
        return new Response<>(Code.UNPROCESSABLE_ENTITY, null, message);
    }

    public static <T> Response<T> failed(T data, String message) {
        return new Response<>(Code.UNPROCESSABLE_ENTITY, data, message);
    }

    public static <T> Response<T> failed(T data, String message, Object extend) {
        return new Response<>(Code.UNPROCESSABLE_ENTITY, data, message, extend);
    }

    /**
     * 未授权，返回401
     */
    public static <T> Response<T> unauthorized(String message) {
        return new Response<>(Code.UNAUTHORIZED, null, message);
    }

    /**
     * 无访问权限，返回403
     */
    public static <T> Response<T> forbidden(String message) {
        return new Response<>(Code.FORBIDDEN, null, message);
    }

    /**
     * 服务器报错，返回500
     */
    public static <T> Response<T> error(String message) {
        return new Response<>(Code.INTERNAL_SERVER_ERROR, null, message);
    }


    /**
     * 304重定向
     */
    public static <T> Response<T> redirect(String location) {
        return new Response<>(Code.NOT_MODIFIED, null, Code.NOT_MODIFIED.getMessage(), new Redirect(location));
    }

    /**
     * 304重定向
     */
    public static <T> Response<T> redirect(String message, String location) {
        return new Response<>(Code.NOT_MODIFIED, null, message, new Redirect(location));
    }

    /**
     * 304重定向
     */
    public static <T> Response<T> redirect(String location, Object extend) {
        return new Response<>(Code.NOT_MODIFIED, null, Code.NOT_MODIFIED.getMessage(), new Redirect(extend, location));
    }

    /**
     * 304重定向
     */
    public static <T> Response<T> redirect(String message, String location, Object extend) {
        return new Response<>(Code.NOT_MODIFIED, null, message, new Redirect(extend, location));
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Redirect {
        private Object data = new Object();
        private String location = "";

        public Redirect(String location) {
            this.location = location;
        }
    }

    @Getter
    public enum Code {
        /**
         * Successful 2xx
         */
        OK(200, true, "成功"),
        CREATED(201, true, "请求已经被实现，而且有一个新的资源已经依据请求的需要而建立。"),
        ACCEPTED(202, true, "服务器已接受请求，但尚未处理。"),
        NO_CONTENT(204, true, "服务器成功处理了请求，但不需要返回任何实体内容。"),

        /**
         * Redirect 3xx
         */
        NOT_MODIFIED(304, false, "对应当前请求的响应可以在另一个 URL 上被找到。"),

        /**
         * Client Error 4xx
         */
        BAD_REQUEST(400, false, "语义有误，当前请求无法被服务器理解。"),
        UNAUTHORIZED(401, false, "当前请求需要用户验证。"),
        FORBIDDEN(403, false, "服务器已经理解请求，但是拒绝执行它。"),
        NOT_FOUND(404, false, "请求失败，请求所希望得到的资源未被在服务器上发现。"),
        UNPROCESSABLE_ENTITY(422, false, "请求格式正确，但是由于含有语义错误，无法响应。"),

        /**
         * Server Error 5xx
         */
        INTERNAL_SERVER_ERROR(500, false, "服务器报错");

        private final int code;
        private final boolean success;
        private final String message;
        private final String description;

        Code(int code, boolean success, String description) {
            this.code = code;
            this.success = success;
            this.message = this.name().replace("_", " ");
            this.description = description;
        }

    }

}
